package com.example.waibao.config;

import com.example.waibao.entity.rank.RankDO;
import com.example.waibao.entity.rank.RankDO2;
import com.example.waibao.entity.rank.rank_score;
import com.example.waibao.entity.rank.speciality_rank_score;
import com.example.waibao.entity.student;
import com.example.waibao.service.RankService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Collections;

@Component
public class RankListComponent {
    @Autowired
    public RedisComponent redisComponent;
    private static  String RANK_PREFIX = "school_rank";
    private static  String RANK_PREFIX2 = "speciality_rank";

    @Autowired
    private RankService rankService;

    private List<RankDO> buildRedisRankToBizDO(Set<ZSetOperations.TypedTuple<String>> result, long offset) {

        List<RankDO> rankList = new ArrayList<>(result.size());
        long rank = offset;
        for (ZSetOperations.TypedTuple<String> sub : result) {
            rankList.add(new RankDO(rank++, Math.abs(sub.getScore().floatValue()), sub.getValue()));
        }
//        Long.parseLong(sub.getValue())
        return rankList;
    }

    private List<RankDO2> buildRedisRankToBizDO2(Set<ZSetOperations.TypedTuple<String>> result, long offset) {

        List<RankDO2> rankList = new ArrayList<>(result.size());
        long rank = offset;
        for (ZSetOperations.TypedTuple<String> sub : result) {
            rankList.add(new RankDO2(rank++, Math.abs(sub.getScore().floatValue()), sub.getValue()));
        }
//        Long.parseLong(sub.getValue())
        return rankList;
    }


    //获取专业排名
    public List<RankDO2> get_speciality_rank(int n, int school_id) {
        RANK_PREFIX2 = "speciality_rank";
        RANK_PREFIX2 = RANK_PREFIX2 + school_id;
        System.out.println("进入");
        Set<ZSetOperations.TypedTuple<String>> result = redisComponent.rangeWithScore(RANK_PREFIX2, 0, n - 1);
        if(result.isEmpty()){
            synchronized (this){
                result = redisComponent.rangeWithScore(RANK_PREFIX2, 0, n - 1);
                if(result.isEmpty()){
                    System.out.println("放入");
                    String s =addAllRank2(school_id);
                    System.out.println(s);
                    result = redisComponent.rangeWithScore(RANK_PREFIX2, 0, n - 1);
                }
            }
        }

        if(result.isEmpty()){
            return Collections.emptyList();
        }

        return buildRedisRankToBizDO2(result, 1);
    }

    /**
     * 获取前 n 名的排行榜数据
     *
     * @param
     * @return
     */
    public List<RankDO> getTopNRanks(int n, int school_id, int speciality_id, int type) {
        RANK_PREFIX = "school_rank";
        RANK_PREFIX = RANK_PREFIX + school_id+speciality_id+type;
        System.out.println("进入");
        Set<ZSetOperations.TypedTuple<String>> result = redisComponent.rangeWithScore(RANK_PREFIX, 0, n - 1);
        if(result.isEmpty()){
            synchronized (this){


                result = redisComponent.rangeWithScore(RANK_PREFIX, 0, n - 1);
                if(result.isEmpty()){
                    System.out.println("放入");
                    String s =addAllRank(school_id, speciality_id,type);
                    System.out.println(s);
                    result = redisComponent.rangeWithScore(RANK_PREFIX, 0, n - 1);
                }
            }
        }

        if(result.isEmpty()){
            return Collections.emptyList();
        }

        return buildRedisRankToBizDO(result, 1);
    }

    /**
     * 获取用户所在排行榜的位置，以及排行榜中其前后 n 个用户的排行信息
     *
     * @param student_name
     * @param n
     * @return
     */
    public List<RankDO> getRankAroundUser(String student_name, int n) {

        //首先是获取用户对应的排名
        RankDO rank = getRank(student_name);
        if (rank.getRank() <= 0) {

            // fixme 用户没有上榜时，不返回
            return Collections.emptyList();
        }

        // 因为实际的排名是从0开始的，所以查询周边排名时，需要将n-1
        Set<ZSetOperations.TypedTuple<String>> result =
                redisComponent.rangeWithScore(RANK_PREFIX, Math.max(0, rank.getRank() - n - 1), rank.getRank() + n - 1);
        return buildRedisRankToBizDO(result, rank.getRank() - n);
    }

    /**
     * 获取用户的排行榜位置
     *
     * @param student_name
     * @return
     */
    public RankDO getRank(String student_name) {
        //获取排行，因为默认是 0 为开头，因此实际的排名需要 + 1
        Long rank = redisComponent.rank(RANK_PREFIX, String.valueOf(student_name));
        if (rank == null) {
            //没有排行时，直接返回一个默认的
            return new RankDO(-1L, 0F, student_name);
        }

        //获取积分
        Double score = redisComponent.score(RANK_PREFIX, String.valueOf(student_name));
        return new RankDO(rank + 1, Math.abs(score.floatValue()), student_name);
    }

    /**
     * 更新用户积分，并获取最新的个人所在排行榜信息
     *
     * @param student_name
     * @param score
     * @return
     */
    public RankDO updateRank(String student_name, Float score) {

        // 因为zset默认积分小的在前面，所以我们对score进行取反，这样用户的积分越大，对应的score越小，排名越高
        redisComponent.add(RANK_PREFIX, String.valueOf(student_name), -score);
        Long rank = redisComponent.rank(RANK_PREFIX, String.valueOf(student_name));
        return new RankDO(rank + 1, score, student_name);
    }

    public String addAllRank(int school_id, int speciality_id, int type){
       List<rank_score> allRank =  rankService.getAllRank(school_id, speciality_id);
       redisComponent.addAll(RANK_PREFIX,allRank, type);
       return "从数据库中获取排名信息并放入到redis中";
    }

    public String addAllRank2(int school_id){
        List<speciality_rank_score> allRank =  rankService.getAllRank2(school_id);
        System.out.println(allRank);
        redisComponent.addAll2(RANK_PREFIX2,allRank);

        return "从数据库中获取排名信息并放入到redis中";
    }

}
